extends Node
class_name LogSystem

# 日志级别
enum LogLevel {
	DEBUG = 0,
	INFO = 1,
	WARNING = 2,
	ERROR = 3,
	NONE = 4  # 用于完全禁用日志
}

# 配置
var current_level: int = LogLevel.DEBUG  # 当前日志级别，低于此级别的日志不会记录
var log_to_console: bool = true  # 是否在控制台输出日志
var log_to_file: bool = true  # 是否将日志写入文件
var log_file_path: String = "user://game_log.txt"  # 日志文件路径
var max_log_size: int = 10 * 1024 * 1024  # 最大日志文件大小（10MB）
var include_stack_trace: bool = true  # 是否在错误日志中包含堆栈跟踪

# 内部变量
var _file: FileAccess = null
var _log_buffer: Array = []
var _buffer_size: int = 100  # 缓冲区大小，达到此数量时写入文件
var _is_flushing: bool = false

func _ready():
	print("LogSystem初始化")
	
	# 创建日志目录
	var dir = DirAccess.open("user://")
	if not dir:
		push_error("无法访问用户目录")
		return
	
	# 检查日志文件大小，如果超过限制则备份并创建新文件
	if FileAccess.file_exists(log_file_path):
		var file_size = FileAccess.get_file_as_bytes(log_file_path).size()
		if file_size > max_log_size:
			var timestamp = Time.get_datetime_string_from_system().replace(":", "-").replace(" ", "_")
			var backup_path = "user://game_log_" + timestamp + ".txt"
			DirAccess.rename_absolute(log_file_path, backup_path)
			info("日志文件已达到最大大小，已备份到: " + backup_path)
	
	# 打开日志文件
	if log_to_file:
		_open_log_file()
	
	# 记录游戏启动信息
	info("===== 游戏启动 =====")
	info("日期时间: " + Time.get_datetime_string_from_system())
	info("Godot版本: " + Engine.get_version_info().string)
	info("操作系统: " + OS.get_name())
	
	# 设置自动保存定时器
	var timer = Timer.new()
	timer.wait_time = 30.0  # 每30秒自动保存一次日志
	timer.one_shot = false
	timer.timeout.connect(_on_flush_timer)
	add_child(timer)
	timer.start()

func _exit_tree():
	info("===== 游戏关闭 =====")
	flush()  # 确保所有日志都被写入文件
	if _file:
		_file.close()

func _open_log_file() -> bool:
	if _file:
		_file.close()
	
	# 尝试以追加模式打开文件
	_file = FileAccess.open(log_file_path, FileAccess.WRITE_READ)
	if not _file:
		push_error("无法打开日志文件: " + log_file_path)
		return false
	
	# 移动到文件末尾以追加内容
	_file.seek_end()
	return true

func debug(message: String, context: String = ""):
	_log(LogLevel.DEBUG, message, context)

func info(message: String, context: String = ""):
	_log(LogLevel.INFO, message, context)

func warning(message: String, context: String = ""):
	_log(LogLevel.WARNING, message, context)

func error(message: String, context: String = "", with_stack: bool = true):
	_log(LogLevel.ERROR, message, context, with_stack)

func _log(level: int, message: String, context: String = "", with_stack: bool = false):
	# 检查日志级别
	if level < current_level:
		return
	
	# 获取当前时间
	var datetime = Time.get_datetime_dict_from_system()
	var timestamp = "%04d-%02d-%02d %02d:%02d:%02d" % [
		datetime.year, datetime.month, datetime.day,
		datetime.hour, datetime.minute, datetime.second
	]
	
	# 获取日志级别文本
	var level_text = ""
	match level:
		LogLevel.DEBUG:
			level_text = "DEBUG"
		LogLevel.INFO:
			level_text = "INFO"
		LogLevel.WARNING:
			level_text = "WARNING"
		LogLevel.ERROR:
			level_text = "ERROR"
	
	# 构建日志条目
	var log_entry = "[%s] [%s]" % [timestamp, level_text]
	if context != "":
		log_entry += " [%s]" % context
	log_entry += ": %s" % message
	
	# 添加堆栈跟踪（如果需要）
	if with_stack and include_stack_trace and level == LogLevel.ERROR:
		log_entry += "\n堆栈跟踪:\n" + get_stack_trace()
	
	# 输出到控制台
	if log_to_console:
		match level:
			LogLevel.DEBUG:
				print(log_entry)
			LogLevel.INFO:
				print(log_entry)
			LogLevel.WARNING:
				push_warning(log_entry)
			LogLevel.ERROR:
				push_error(log_entry)
	
	# 添加到缓冲区
	if log_to_file:
		_log_buffer.append(log_entry)
		
		# 如果缓冲区达到一定大小，写入文件
		if _log_buffer.size() >= _buffer_size:
			flush()

func flush():
	if _is_flushing or not log_to_file or _log_buffer.size() == 0:
		return
	
	_is_flushing = true
	
	if not _file or not _file.is_open():
		if not _open_log_file():
			_is_flushing = false
			return
	
	# 写入所有缓冲的日志
	for entry in _log_buffer:
		_file.store_line(entry)
	
	# 清空缓冲区
	_log_buffer.clear()
	
	# 确保数据写入磁盘
	_file.flush()
	
	_is_flushing = false

func _on_flush_timer():
	flush()

func get_stack_trace() -> String:
	var stack = get_stack()
	var trace = ""
	
	# 跳过前两个堆栈帧（get_stack_trace和_log函数）
	for i in range(2, stack.size()):
		var frame = stack[i]
		trace += "  在 %s:%d - 函数: %s()\n" % [frame.source, frame.line, frame.function]
	
	return trace

func set_level(level: int):
	current_level = level

func enable_file_logging(enable: bool):
	log_to_file = enable
	if enable and not _file:
		_open_log_file()

func enable_console_logging(enable: bool):
	log_to_console = enable

func set_log_file_path(path: String):
	if path == log_file_path:
		return
	
	# 保存当前日志
	flush()
	if _file:
		_file.close()
		_file = null
	
	log_file_path = path
	
	if log_to_file:
		_open_log_file()